{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# VeighNa XT 交易接口演示\n",
    "\n",
    "本演示基于vnpy_xt模块，专注于交易相关功能，包括初始化交易网关、事件处理、下单撤单操作、模拟交易演示以及账户和持仓查询。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. 导入必要的库"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 导入VeighNa核心库\n",
    "import sys\n",
    "sys.path.append('d:/git/liugejiao/vnpy')  # 添加包含vnpy模块的目录\n",
    "sys.path.append('d:/git/liugejiao')  # 添加项目根目录\n",
    "from vnpy.event import EventEngine\n",
    "from vnpy.trader.constant import Exchange, Interval, Direction, Offset, OrderType\n",
    "from vnpy.trader.object import SubscribeRequest, OrderRequest, CancelRequest\n",
    "from vnpy.trader.event import EVENT_ORDER, EVENT_TRADE, EVENT_ACCOUNT, EVENT_POSITION, EVENT_TICK\n",
    "\n",
    "# 导入XT相关模块\n",
    "sys.path.append('d:/git/liugejiao/vnpy_xt')  # 添加vnpy_xt的父目录\n",
    "from vnpy_xt import XtGateway, Datafeed\n",
    "\n",
    "# 导入其他必要库\n",
    "import pandas as pd\n",
    "from datetime import datetime, timedelta\n",
    "import time"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. 初始化交易网关 (Gateway)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 创建事件引擎\n",
    "event_engine = EventEngine()\n",
    "event_engine.start()\n",
    "\n",
    "# 创建交易网关实例\n",
    "gateway = XtGateway(event_engine, \"XT\")\n",
    "\n",
    "# 定义事件处理函数\n",
    "def process_order_event(event):\n",
    "    \"\"\"处理订单事件\"\"\"\n",
    "    order = event.data\n",
    "    print(f\"订单更新: {order.vt_symbol} {order.direction.value} {order.offset.value} {order.status.value} 价格: {order.price}, 数量: {order.volume}, 成交: {order.traded} 时间: {order.datetime}\")\n",
    "\n",
    "def process_trade_event(event):\n",
    "    \"\"\"处理成交事件\"\"\"\n",
    "    trade = event.data\n",
    "    print(f\"成交回报: {trade.vt_symbol} {trade.direction.value} {trade.offset.value} 价格: {trade.price}, 数量: {trade.volume} 时间: {trade.datetime}\")\n",
    "\n",
    "def process_account_event(event):\n",
    "    \"\"\"处理账户事件\"\"\"\n",
    "    account = event.data\n",
    "    print(f\"账户更新: {account.accountid} 总资产: {account.total_value}, 可用资金: {account.available} 冻结资金: {account.frozen}\")\n",
    "    \n",
    "    # 直接从gateway获取账户数据并打印\n",
    "    if hasattr(gateway, 'accounts'):\n",
    "        print(\"直接从gateway获取的账户数据：\")\n",
    "        for acc_id, acc in gateway.accounts.items():\n",
    "            print(f\"  - 账户ID: {acc_id} 总资产: {acc.total_value} 可用资金: {acc.available} 冻结资金: {acc.frozen}  持仓市值: {acc.position_value}\")\n",
    "\n",
    "def process_position_event(event):\n",
    "    \"\"\"处理持仓事件\"\"\"\n",
    "    position = event.data\n",
    "    print(f\"持仓更新: {position.vt_symbol} {position.direction.value} 持仓量: {position.volume}, 可用量: {position.available} 开仓均价: {position.price}, 浮动盈亏: {position.pnl}\")\n",
    "    \n",
    "    # 直接从gateway获取持仓数据并打印\n",
    "    if hasattr(gateway, 'positions'):\n",
    "        print(\"直接从gateway获取的持仓数据：\")\n",
    "        for pos_key, pos in gateway.positions.items():\n",
    "            print(f\"  - 合约: {pos.vt_symbol} 方向: {pos.direction.value} 持仓量: {pos.volume} 可用量: {pos.available} 开仓均价: {pos.price} 浮动盈亏: {pos.pnl}\")\n",
    "\n",
    "def process_tick_event(event):\n",
    "    \"\"\"处理行情事件\"\"\"\n",
    "    tick = event.data\n",
    "    print(f\"行情推送: {tick.vt_symbol} 最新价: {tick.last_price} 成交量: {tick.volume} 时间: {tick.datetime}\")\n",
    "\n",
    "# 注册事件监听\n",
    "event_engine.register(EVENT_ORDER, process_order_event)\n",
    "event_engine.register(EVENT_TRADE, process_trade_event)\n",
    "event_engine.register(EVENT_ACCOUNT, process_account_event)\n",
    "event_engine.register(EVENT_POSITION, process_position_event)\n",
    "event_engine.register(EVENT_TICK, process_tick_event)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 配置连接参数\n",
    "# 注意：使用客户端模式连接需要确保迅投客户端已启动\n",
    "setting = {\n",
    "    \"token\": \"\",  # 客户端模式下token可以留空\n",
    "    \"股票市场\": \"是\",\n",
    "    \"期货市场\": \"否\",\n",
    "    \"期权市场\": \"否\",\n",
    "    \"仿真交易\": \"是\",  # 请根据实际情况修改\n",
    "    \"账号类型\": \"股票\",\n",
    "    \"QMT路径\": r\"D:/gjzqqmt_ceshi\",  # 请修改为您的QMT安装路径\n",
    "    \"资金账号\": \"40743071\"  # 替换为您的资金账号\n",
    "}\n",
    "\n",
    "# 连接交易网关\n",
    "print(\"连接交易网关中...\")\n",
    "gateway.connect(setting)\n",
    "# 增加等待时间，确保连接完全建立\n",
    "print(\"等待连接完全建立...\")\n",
    "time.sleep(5)\n",
    "\n",
    "# 主动获取账户和持仓数据\n",
    "print(\"初始化请求账户和持仓数据...\")\n",
    "gateway.query_account()\n",
    "gateway.query_position()\n",
    "time.sleep(3)  # 等待数据返回"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. 委托下单操作"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 下单操作\n",
    "def place_order(symbol, exchange, direction, offset, price, volume):\n",
    "    \"\"\"下单函数\"\"\"\n",
    "    req = OrderRequest(\n",
    "        symbol=symbol,\n",
    "        exchange=exchange,\n",
    "        direction=direction,\n",
    "        offset=offset,\n",
    "        type=OrderType.LIMIT,\n",
    "        price=price,\n",
    "        volume=volume\n",
    "    )\n",
    "    order_id = gateway.send_order(req)\n",
    "    print(f\"下单成功，订单号: {order_id}\")\n",
    "    return order_id\n",
    "\n",
    "# 撤单操作\n",
    "def cancel_order(order_id, symbol, exchange):\n",
    "    \"\"\"撤单函数\"\"\"\n",
    "    req = CancelRequest(\n",
    "        orderid=order_id,\n",
    "        symbol=symbol,\n",
    "        exchange=exchange\n",
    "    )\n",
    "    gateway.cancel_order(req)\n",
    "    print(f\"撤单请求已发送，订单号: {order_id}\")\n",
    "\n",
    "# 示例：买入100股平安银行（取消注释使用）\n",
    "# 注意：实际运行前请修改价格为最新行情价格\n",
    "# order_id = place_order(\"000001\", Exchange.SZSE, Direction.LONG, Offset.NONE, 10.0, 100)\n",
    "\n",
    "# 示例：撤单（取消注释使用）\n",
    "# 注意：实际运行前请修改order_id为实际下单返回的订单号\n",
    "# order_id = \"12345678901234567890\"\n",
    "# if order_id:\n",
    "#     cancel_order(order_id, \"000001\", Exchange.SZSE)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4. 模拟交易完整示例"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 模拟交易完整示例 - 适合模拟QMT终端\n",
    "def run_simulated_trading_demo():\n",
    "    \"\"\"模拟交易完整示例\"\"\"\n",
    "    print(\"=== 开始模拟交易演示 ===\")\n",
    "    \n",
    "    # 1. 先查询账户信息，确认资金状况\n",
    "    print(\"1. 查询当前账户信息...\")\n",
    "    gateway.query_account()\n",
    "    time.sleep(3)  # 增加等待时间确保数据返回\n",
    "    \n",
    "    # 直接从gateway获取账户数据并打印\n",
    "    if hasattr(gateway, 'accounts'):\n",
    "        print(\"当前账户列表: \")\n",
    "        for acc_id, acc in gateway.accounts.items():\n",
    "            print(f\"  - 账户: {acc_id}  总资产: {acc.total_value} 可用资金: {acc.available} 冻结资金: {acc.frozen} 持仓市值: {acc.position_value}\")\n",
    "    else:\n",
    "        print(\"网关暂未获取到账户数据，请检查连接状态\")\n",
    "    \n",
    "    # 2. 查询当前持仓\n",
    "    print(\"2. 查询当前持仓...\")\n",
    "    gateway.query_position()\n",
    "    time.sleep(3)  # 增加等待时间确保数据返回\n",
    "    \n",
    "    # 直接从gateway获取持仓数据并打印\n",
    "    if hasattr(gateway, 'positions'):\n",
    "        if gateway.positions:\n",
    "            print(\"当前持仓列表: \")\n",
    "            for pos_key, pos in gateway.positions.items():\n",
    "                print(f\"  - 合约: {pos.vt_symbol}  方向: {pos.direction.value}  持仓量: {pos.volume}  可用量: {pos.available}  开仓均价: {pos.price}  浮动盈亏: {pos.pnl}\")\n",
    "        else:\n",
    "            print(\"当前无持仓\")\n",
    "    else:\n",
    "        print(\"网关暂未获取到持仓数据，请检查连接状态\")\n",
    "    \n",
    "    # 3. 下单操作 - 买入少量平安银行股票进行测试\n",
    "    # 注意：使用合理的价格参数，避免价格过高或过低\n",
    "    print(\"3. 执行买入操作...\")\n",
    "    # 获取平安银行合约信息中的昨收价作为参考价格\n",
    "    ref_price = 10.0  # 可以根据实际行情修改\n",
    "    order_id = place_order(\"000001\", Exchange.SZSE, Direction.LONG, Offset.NONE, ref_price, 100)\n",
    "    time.sleep(3)  # 等待订单确认\n",
    "    \n",
    "    # 4. 再次查询持仓，查看是否有新持仓\n",
    "    if order_id:\n",
    "        print(\"4. 再次查询持仓，确认买入结果...\")\n",
    "        gateway.query_position()\n",
    "        time.sleep(2)\n",
    "    \n",
    "    # 5. 演示下单操作 - 买入少量沪深300ETF\n",
    "    print(\"5. 执行沪深300ETF买入操作...\")\n",
    "    etf_price = 4.7  # 可以根据实际行情修改\n",
    "    etf_order_id = place_order(\"510300\", Exchange.SSE, Direction.LONG, Offset.NONE, etf_price, 1000)\n",
    "    time.sleep(3)\n",
    "    \n",
    "    # 6. 查询所有订单状态\n",
    "    print(\"6. 查询所有订单状态...\")\n",
    "    gateway.query_order()\n",
    "    time.sleep(2)\n",
    "    \n",
    "    # 7. 如果有未成交订单，可以演示撤单（可选）\n",
    "    # 注意：在模拟环境中，订单可能很快成交，撤单可能不会成功\n",
    "    if etf_order_id:\n",
    "        print(\"7. 演示撤单操作（如果订单未成交）...\")\n",
    "        cancel_order(etf_order_id, \"510300\", Exchange.SSE)\n",
    "        time.sleep(2)\n",
    "    \n",
    "    # 8. 最终查询账户和持仓信息\n",
    "    print(\"8. 最终查询账户和持仓信息...\")\n",
    "    gateway.query_account()\n",
    "    time.sleep(1)\n",
    "    gateway.query_position()\n",
    "    time.sleep(1)\n",
    "    \n",
    "    # 直接从gateway获取最终的账户和持仓数据\n",
    "    print(\"9. 直接从gateway获取最终账户和持仓信息...\")\n",
    "    # 再次查询确保数据最新\n",
    "    gateway.query_account()\n",
    "    gateway.query_position()\n",
    "    time.sleep(1)\n",
    "    \n",
    "    # 打印账户信息\n",
    "    if hasattr(gateway, 'accounts'):\n",
    "        print(\"最终账户信息: \")\n",
    "        for acc_id, acc in gateway.accounts.items():\n",
    "            print(f\"  - 账户: {acc_id}  总资产: {acc.total_value}  可用资金: {acc.available}  冻结资金: {acc.frozen}  持仓市值: {acc.position_value}\")\n",
    "    \n",
    "    # 打印持仓信息\n",
    "    if hasattr(gateway, 'positions'):\n",
    "        if gateway.positions:\n",
    "            print(\"最终持仓信息: \")\n",
    "            for pos_key, pos in gateway.positions.items():\n",
    "                print(f\"  - 合约: {pos.vt_symbol}  方向: {pos.direction.value} 持仓量: {pos.volume} 可用量: {pos.available}  开仓均价: {pos.price}  浮动盈亏: {pos.pnl}\")\n",
    "        else:\n",
    "            print(\"最终仍无持仓\")\n",
    "    \n",
    "    print(\"=== 模拟交易演示结束 ===\")\n",
    "\n",
    "# 运行模拟交易演示（取消注释下面一行来执行）\n",
    "run_simulated_trading_demo()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5. 简单交易策略示例"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义获取历史数据的函数（用于策略分析）\n",
    "def get_stock_history(symbol, exchange, interval, days=30):\n",
    "    \"\"\"获取股票历史数据\"\"\"\n",
    "    # 创建数据服务实例\n",
    "    datafeed = Datafeed()\n",
    "    datafeed.username = \"client\"\n",
    "    \n",
    "    if not datafeed.init():\n",
    "        print(f\"数据服务初始化失败，无法获取{symbol}历史数据\")\n",
    "        return None\n",
    "    \n",
    "    # 计算起止时间\n",
    "    end = datetime.now()\n",
    "    start = end - timedelta(days=days)\n",
    "    \n",
    "    # 创建历史数据请求\n",
    "    from vnpy.trader.object import HistoryRequest\n",
    "    req = HistoryRequest(\n",
    "        symbol=symbol,\n",
    "        exchange=exchange,\n",
    "        interval=interval,\n",
    "        start=start,\n",
    "        end=end\n",
    "    )\n",
    "    \n",
    "    # 查询数据\n",
    "    bars = datafeed.query_bar_history(req)\n",
    "    \n",
    "    if bars:\n",
    "        # 转换为DataFrame格式便于查看和分析\n",
    "        df = pd.DataFrame(\n",
    "            [[bar.datetime, bar.open_price, bar.high_price, bar.low_price, bar.close_price, bar.volume]\n",
    "             for bar in bars],\n",
    "            columns=[\"datetime\", \"open\", \"high\", \"low\", \"close\", \"volume\"]\n",
    "        )\n",
    "        return df\n",
    "    else:\n",
    "        print(f\"无法获取 {symbol} 的历史数据\")\n",
    "        return None\n",
    "\n",
    "# 模拟交易策略示例 - 简单的均线交叉策略\n",
    "def simple_ma_strategy_demo(symbol, exchange, fast_period=5, slow_period=20, volume=100):\n",
    "    \"\"\"简单的均线交叉交易策略演示\"\"\"\n",
    "    print(f\"=== 开始均线交叉策略演示 ({symbol}.{exchange.value}) ===\")\n",
    "    \n",
    "    # 1. 获取历史数据\n",
    "    print(f\"1. 获取{symbol}的历史数据...\")\n",
    "    df = get_stock_history(symbol, exchange, Interval.DAILY, days=60)\n",
    "    \n",
    "    if df is None:\n",
    "        print(f\"无法获取{symbol}的历史数据，策略终止\")\n",
    "        return\n",
    "    \n",
    "    # 2. 计算均线\n",
    "    print(\"2. 计算均线指标...\")\n",
    "    df['fast_ma'] = df['close'].rolling(window=fast_period).mean()\n",
    "    df['slow_ma'] = df['close'].rolling(window=slow_period).mean()\n",
    "    \n",
    "    # 3. 生成交易信号\n",
    "    df['signal'] = 0  # 0: 无信号, 1: 买入, -1: 卖出\n",
    "    df.loc[df['fast_ma'] > df['slow_ma'], 'signal'] = 1\n",
    "    df.loc[df['fast_ma'] <= df['slow_ma'], 'signal'] = -1\n",
    "    \n",
    "    # 4. 获取最新信号和价格\n",
    "    latest = df.iloc[-1]\n",
    "    signal = latest['signal']\n",
    "    latest_price = latest['close']\n",
    "    \n",
    "    print(f\"3. 最新信号分析:\")\n",
    "    print(f\"   - 当前价格: {latest_price}\")\n",
    "    print(f\"   - {fast_period}日均线: {latest['fast_ma']:.2f}\")\n",
    "    print(f\"   - {slow_period}日均线: {latest['slow_ma']:.2f}\")\n",
    "    \n",
    "    # 5. 根据信号执行交易\n",
    "    if signal == 1:\n",
    "        print(f\"4. 信号: 买入信号（快线{fast_period}上穿慢线{slow_period}）\")\n",
    "        order_id = place_order(symbol, exchange, Direction.LONG, Offset.NONE, latest_price, volume)\n",
    "    elif signal == -1:\n",
    "        print(f\"4. 信号: 卖出信号（快线{fast_period}下穿慢线{slow_period}）\")\n",
    "        # 在模拟环境中，我们也可以尝试卖出操作（如果有持仓）\n",
    "        order_id = place_order(symbol, exchange, Direction.SHORT, Offset.NONE, latest_price, volume)\n",
    "    else:\n",
    "        print(\"4. 信号: 无明确交易信号\")\n",
    "        order_id = None\n",
    "    \n",
    "    print(\"=== 均线交叉策略演示结束 ===\")\n",
    "    return order_id\n",
    "\n",
    "# 运行均线策略演示（取消注释下面一行来执行）\n",
    "# simple_ma_strategy_demo(\"510300\", Exchange.SSE, fast_period=5, slow_period=20, volume=1000)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 6. 账户和持仓查询"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 查询账户信息\n",
    "print(\"查询账户信息...\")\n",
    "gateway.query_account()\n",
    "time.sleep(1)\n",
    "\n",
    "# 查询持仓信息\n",
    "print(\"查询持仓信息...\")\n",
    "gateway.query_position()\n",
    "time.sleep(1)\n",
    "\n",
    "# 直接从gateway获取并打印账户和持仓信息\n",
    "print(\"直接从gateway获取的账户和持仓信息：\")\n",
    "\n",
    "# 打印账户信息\n",
    "if hasattr(gateway, 'accounts'):\n",
    "    if gateway.accounts:\n",
    "        print(\"账户列表: \")\n",
    "        for acc_id, acc in gateway.accounts.items():\n",
    "            print(f\"  - 账户: {acc_id} 总资产: {acc.total_value}  可用资金: {acc.available} 冻结资金: {acc.frozen} 持仓市值: {acc.position_value}\")\n",
    "    else:\n",
    "        print(\"当前无账户信息\")\n",
    "else:\n",
    "    print(\"网关暂未获取到账户数据，请检查连接状态\")\n",
    "\n",
    "# 打印持仓信息\n",
    "if hasattr(gateway, 'positions'):\n",
    "    if gateway.positions:\n",
    "        print(\"持仓列表: \")\n",
    "        for pos_key, pos in gateway.positions.items():\n",
    "            print(f\"  - 合约: {pos.vt_symbol}  方向: {pos.direction.value}  持仓量: {pos.volume}  可用量: {pos.available}  开仓均价: {pos.price}  浮动盈亏: {pos.pnl}\")\n",
    "    else:\n",
    "        print(\"当前无持仓\")\n",
    "else:\n",
    "    print(\"网关暂未获取到持仓数据，请检查连接状态\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 7. 关闭连接"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 关闭交易网关\n",
    "print(\"关闭交易网关...\")\n",
    "gateway.close()\n",
    "\n",
    "# 停止事件引擎\n",
    "print(\"停止事件引擎...\")\n",
    "event_engine.stop()\n",
    "\n",
    "print(\"交易接口演示完成！\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 8. 注意事项"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. 使用本演示前，请确保：\n",
    "   - 已安装vnpy_xt模块\n",
    "   - 已安装并启动迅投QMT客户端\n",
    "   - 已正确配置QMT路径和资金账号\n",
    "\n",
    "2. 实盘交易前，请先在模拟环境中充分测试\n",
    "\n",
    "3. 下单操作需要根据实时行情设置合理的价格\n",
    "\n",
    "4. 为了确保能够成功获取账户和持仓信息，我们增加了连接等待时间和主动请求机制\n",
    "\n",
    "5. 本演示主要针对股票和ETF市场的交易功能"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "liugejiao",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
